package org.github.manx98.jlibhac.tools.es;

import org.github.manx98.jlibhac.common.keys.KeySet;
import org.github.manx98.jlibhac.common.math.Uint16;
import org.github.manx98.jlibhac.common.math.Uint32;
import org.github.manx98.jlibhac.common.math.Uint64;
import org.github.manx98.jlibhac.fs.IStorage;
import org.github.manx98.jlibhac.tools.crypto.CryptoOld;

import java.io.IOException;

/**
 * @author Manx98
 * @version 1.0
 * @since 2022/10/3 17:33
 */
public class Ticket {
    public final TicketSigType SignatureType;
    public final byte[] Signature;
    public final String Issuer;
    public final byte[] TitleKeyBlock;
    public final byte formatVersion;
    public final TitleKeyType titleKeyType;
    public final Uint16 TicketVersion;
    public final byte LicenseType;
    public final byte CryptoType;
    public final Uint32 PropertyMask;
    public final Uint64 TicketId;
    public final Uint64 DeviceId;
    public final byte[] RightsId;
    public final Uint32 AccountId;
    public final int SectTotalSize;
    public final int SectHeaderOffset;
    public final short SectNum;
    public final short SectEntrySize;
    public final byte[] File;

    public Ticket(IStorage reader) throws IOException {
        long fileStart = reader.getPosition();
        this.SignatureType = TicketSigType.valueOf(reader.readInt());

        switch (SignatureType) {
            case Rsa4096Sha1:
            case Rsa4096Sha256:
                this.Signature = reader.readBytes(0x200);
                reader.readBytes(0x3c);
                break;
            case Rsa2048Sha1:
            case Rsa2048Sha256:
                this.Signature = reader.readBytes(0x100);
                reader.readBytes(0x3c);
                break;
            case EcdsaSha1:
            case EcdsaSha256:
                Signature = reader.readBytes(0x3c);
                reader.readBytes(0x40);
                break;
            default:
                throw new IllegalArgumentException("Unknown signature type: " + SignatureType);
        }

        long dataStart = reader.getPosition();

        this.Issuer = reader.readUtf8Z(0x40);
        reader.setPosition(dataStart + 0x40);
        this.TitleKeyBlock = reader.readBytes(0x100);
        this.formatVersion = reader.readByte();
        this.titleKeyType = TitleKeyType.valueOf(reader.readByte());
        this.TicketVersion = reader.readUint16();
        this.LicenseType = reader.readByte();
        this.CryptoType = reader.readByte();
        this.PropertyMask = reader.readUint32();
        reader.setPosition(dataStart + 0x150);
        this.TicketId = reader.readUint64();
        this.DeviceId = reader.readUint64();
        this.RightsId = reader.readBytes(0x10);
        this.AccountId = reader.readUint32();
        this.SectTotalSize = reader.readInt();
        this.SectHeaderOffset = reader.readInt();
        this.SectNum = reader.readShort();
        this.SectEntrySize = reader.readShort();

        reader.setPosition(fileStart);
        this.File = reader.readBytes(SectHeaderOffset);
    }

    public byte[] getTitleKey(KeySet keySet) {
        if (this.titleKeyType == TitleKeyType.Common) {
            byte[] commonKey = new byte[0x10];
            System.arraycopy(TitleKeyBlock, 0, commonKey, 0, commonKey.length);
            return commonKey;
        }
        return CryptoOld.decryptRsaOaep(TitleKeyBlock, keySet.ETicketExtKeyRsa);
    }
}
